package zasm.zasm.assembler;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

import zasm.zasm.instruction.InstructionSet;
import zasm.zasm.listing.ListingWriter;

public class Assembler {

	private static final String		NAME					= "zasm";

	private static final Pattern	TABLE_DIRECTIVE_PATTERN	= Pattern.compile("\\.([^\\s]+).*");
	private static final Pattern	INSRTUCTION_PATTERN		= Pattern.compile("([a-z][^\\s,]*)\\s+"
																	+ "([^\\s,]+(?:,[^\\s,]+)*)\\s+"
																	+ "([0-9a-f]{2})+\\s+" + "([0-9]+)\\s+");

	public static void main(final String[] args) {
		final Options options = new Options();
		final Option d = new Option("d", "define a macro");
		d.setArgs(Option.UNLIMITED_VALUES);
		options.addOption(d);
		options.addOption("e", false, "expand macros in the listing file");
		options.addOption("h", false, "print this help");
		options.addOption("q", false, "quiet; disable the listing file");
		options.addOption("t", true, "specify table (default: ZASM80.tab)");
		options.addOption("x", true, "extend instruction set");

		boolean printHelp = true;

		try {
			final CommandLine cl = new PosixParser().parse(options, args);

			if (!cl.hasOption("h")) {

				printHelp = false;
				System.out.println(Arrays.asList(cl.getOptions()));
				System.out.println(cl.getArgList());

				@SuppressWarnings("unchecked")
				final List<String> argList = cl.getArgList();
			}

		} catch (ParseException e) {
			System.out.println(e.getMessage());
		}

		if (printHelp) {
			new HelpFormatter().printHelp(NAME, options);
		}
	}

	private final boolean			expandMacros;
	private final boolean			quiet;
	private final int				extendMask;
	private final InstructionSet	instructionSet;
	private ListingWriter			listWriter;

	public Assembler(final String[] definedMacros, final boolean expandMacros, final boolean quiet, final String table,
			final int extendMask) throws FileNotFoundException, IOException {
		for (String name : definedMacros) {
			define(name);
		}

		try (final BufferedReader reader = new BufferedReader(new FileReader(table))) {
			boolean msFirst = false, altWild = false;
			String line;
			while ((line = reader.readLine()) != null) {
				final char firstChar = line.charAt(0);
				if (Character.isAlphabetic(firstChar)) {
					break;
				}
				final Matcher directiveMatcher = TABLE_DIRECTIVE_PATTERN.matcher(line);
				if (directiveMatcher.matches()) {
					final String directive = directiveMatcher.group(1);
					if (directive.equalsIgnoreCase("MSFIRST")) {
						msFirst = true;
					} else if (directive.equalsIgnoreCase("ALTWILD")) {
						altWild = true;
					} else {
						// TODO: trigger some error
					}
				}
			}
			instructionSet = new InstructionSet(null, msFirst);
			while ((line = reader.readLine()) != null) {
				final char firstChar = line.charAt(0);
				if (Character.isAlphabetic(firstChar)) {

				} else {
					final Matcher directiveMatcher = TABLE_DIRECTIVE_PATTERN.matcher(line);
					if (directiveMatcher.matches()) {
						// TODO: trigger some error
					}
				}
			}
		}

		this.expandMacros = expandMacros;
		this.quiet = quiet;
		this.extendMask = extendMask;
	}

	protected void define(final String name) {}

	protected void define(final String name, final String value) {}

}
